#!/usr/bin/env python
#coding=utf-8

import re
import os
import time
import logging
from xsl import XLSWriter

from vic.exchange.vic_binance.binance_http import BinaHttp
from lib.common import excel_folder_path, config_data, log_info, \
            log_exception, timestamp2str, current_strtime,\
            before_after_timestamp, get_symbol



class BinanService(BinaHttp):
    """BinanService"""
    def __init__(self, url, apikey, apisecret):
        super(BinaHttp, self).__init__(url, apikey, apisecret)
        self.url       = url
        self.apikey    = apikey
        self.apisecret = apisecret
        self.msg       = ''
        self.http      = BinaHttp(url, apikey, apisecret)

    def account(self):
        """币安账户信息"""
        account_info = self.http.account()
        return account_info


    def balances_list(self):
        """币安余额信息列表"""
        account = self.account()
        try:
            balances = account.get('balances')
        except Exception as e:
            logging.exception('### error', e)
            raise e

        return balances

    def tousdt_rate(self, currency):
        """币安转usdt比率"""

        currency = currency.upper()
        if currency == 'USDT':
            rate = 1
            return rate
        else:
            #usdt_ticker = self.http.ticker(currency+'USDT')
            #if usdt_ticker:
            #    rate = float(usdt_ticker['bidPrice'])
            #else:
            #    tobtc_rate = self.currency_tobch_rate(currency)
            #    btc_ticker = self.http.ticker('BTCUSDT')
            #    btc_tousdt_rate = float(btc_ticker['bidPrice'])
            #    rate = tobtc_rate*btc_tousdt_rate
            tousdt_list = self.conf_currency_tousdt_list()
            if currency not in tousdt_list:
                tobtc_rate = self.currency_tobch_rate(currency)
                btc_ticker = self.http.ticker('BTCUSDT')
                btc_tousdt_rate = float(btc_ticker['bidPrice'])
                rate = tobtc_rate*btc_tousdt_rate
            else:
                usdt_ticker = self.http.ticker(currency+'USDT')
                rate = float(usdt_ticker['bidPrice'])
        return rate


    def currency_list(self):
        """币安币种列表"""
        balances_list = self.balances_list()
        currency = [balances['asset'] for balances in balances_list if float(balances['free']) + float(balances['locked']) >  0]
        return currency

    def sum_usdt(self):
        """币安所有币种转usdt的总数"""

        _sum = 0
        currency_list = self.currency_list()
        balances_list = self.balances_list()
        balances_list = sorted(balances_list, key=lambda a: a["asset"], reverse=False) # ¶ÔÁÐ±íÖÐµÄ×Öµä°´assetµÄÖµÅÅÐò
        for balance in balances_list:
            locked = float(balance['locked'])
            freed  = float(balance['free'])
            asset  = balance['asset']

            if asset not in currency_list:
                continue

            if locked>0 or freed>0:
                if asset =='USDT':
                    rate = 1
                else:
                    rate = self.tousdt_rate(asset)

                _sum += (freed+locked)*rate

        return _sum


    def conf_currency_tousdt_list(self):
        """获取配置文件币种转usdt的列表"""
        currency_tousdt_list = []
        file = "../conf/binance-market-channels.txt"
        with open(file, 'r') as f:
            data      = f.read()
            data      = data.replace('\r', '')
            data_list = data.split('\n')
            for d in data_list:
                d_list = re.split(r'[\-\,]+', d)
                if not d_list[0] or d_list[0] != 'BINA' or d_list[2] != 'USDT':
                    continue # 不是BINA开头和USDT结尾的就循环下一个
                currency_tousdt_list.append(d_list[1])

        return currency_tousdt_list


    def conf_currency_tobtc_list(self):
        """获取配置文件币种转btc的列表"""
        currency_tobtc_list = []
        file = "../conf/binance-market-channels.txt"
        with open(file, 'r') as f:
            data      = f.read()
            data      = data.replace('\r', '')
            data_list = data.split('\n')
            for d in data_list:
                d_list = re.split(r'[\-\,]+', d)
                if not d_list[0] or d_list[0] != 'BINA' or d_list[2] != 'BTC':
                    continue # 不是BINA开头和BTC结尾的就循环下一个
                currency_tobtc_list.append(d_list[1])

        return currency_tobtc_list


    def conf_currency_toeth_list(self):
        """获取配置文件币种转eth的列表"""
        currency_toeth_list = []
        file = "../conf/binance-market-channels.txt"
        with open(file, 'r') as f:
            data      = f.read()
            data      = data.replace('\r', '')
            data_list = data.split('\n')
            for d in data_list:
                d_list = re.split(r'[\-\,]+', d)
                if not d_list[0] or d_list[0] != 'BINA' or d_list[2] != 'ETH':
                    continue # 不是BINA开头和ETH结尾的就循环下一个
                currency_toeth_list.append(d_list[1])

        return currency_toeth_list


    def currency_tobch_rate(self, currency):
        """币种转usdt的比率"""
        currency = currency.upper()
        if currency == 'BTC':
            bidPrice = 1
            return bidPrice

        ticker = self.http.ticker(currency+'BTC')
        rate = float(ticker['bidPrice'])
        return rate

    def currency_tousdt(self, currency):
        """币种转usdt的值"""

        balance = self.currency_balance(currency)
        rate = self.tousdt_rate(currency)
        usdt = float(balance*rate)
        return usdt

    def currency_balance(self, currency):
        """币种余额"""

        balance = 0
        balances_list = self.balances_list()
        for b in balances_list:
            asset  = b['asset']
            if asset == currency:
                locked = float(b['locked'])
                freed  = float(b['free'])
                balance = freed + locked
                break
        return balance


    def bina_cancel_order(self, currency, to_currency='usdt'):
        """币安撤单"""

        error_msg, success_msg = {}, {}
        symbol     = get_symbol(currency, to_currency, 'bina')
        order_list = self.openorders()
        error_list, success_list = [], []
        if not order_list:
            log_info(u'币安无单可撤!')
            return False

        for order in order_list:
            orderId = order.get('orderId')
            self.cancel_order(symbol, orderId)
            status_code = self.status_code
            if status_code != 200:
                error_msg['orderId'] = orderId
                error_list.append(error_msg)
                log_info(u'币安撤单失败!, orderId:%s'% orderId)
            else:
                success_msg['orderId'] = orderId
                success_list.append(success_msg)
                log_info(u'币安撤单成功!, orderId:%s'% orderId)

        if len(error_list) > 0:
            return False

        return True


    def bina_cancel_allorder(self, currency=''):
        """币安撤销所有能撤销的订单"""

        balances_list = self.balances_list()
        for b in balances_list:
            asset  = b.get('asset')
            locked = float(b.get('locked'))

            if asset == 'usdt' or asset not in (currency.upper(), currency.lower()):
                continue # 过滤不是要撤销的币种

            if locked > 0:
                self.bina_cancel_order(asset, 'usdt')

        return True


    def symbol_order(self, symbol, quantity):
        """symbol下单"""

        price = self.symbol_latest_price(symbol)
        quantity = '%.2f' % quantity
        if float(quantity) <= 0:
            return False

        self.http.place_order(symbol, quantity, price, type='MARKET', side='SELL')
        log_info('### json:%s'% self.http.json)
        log_info(u'%s  下单价格:%s, 下单量:%s, 成功!'% (symbol, price, quantity))
        return True


    def symbol_latest_price(self, symbol):
        """symbol最新价格"""
        lp           = self.latest_price(symbol)
        latest_price = float(lp.get('price')) # symbol最新价格
        return latest_price


    def account_order(self, quantity, currency='', multiple=''):
        """账户下单"""
        tousdt_list = self.conf_currency_tousdt_list()
        if currency and currency in tousdt_list:
            symbol = get_symbol(currency, 'usdt', 'bina')
            self.symbol_order(symbol, quantity)
        else:
            balances_list = self.balances_list()
            for b in balances_list:
                asset    = b.get('asset')
                free     = float(b.get('free'))
                quantity = free*float(multiple)
                to_balance = free - quantity
                if asset == 'USDT' or asset not in tousdt_list:
                    continue

                if currency and asset not in (currency.upper(), currency.lower()):
                    continue

                if free > 0:
                    symbol = get_symbol(asset, 'usdt', 'bina')
                    self.symbol_order(symbol, quantity)
                    log_info(u'%s:递归下单开始'% symbol)
                    self.accounts_recursion(asset, to_balance)
                    log_info(u'%s:递归下单结束'% symbol)
        return True


    def excel_export(self, sheet_name, export_title, export_list):
        """导出excel"""

        file_path = u'%s/' % excel_folder_path()
        file = file_path + u'%s'% sheet_name

        xlswriter  = XLSWriter(file=file.encode('utf8'))
        xlswriter.writerow(export_title, sheet_name=sheet_name)

        sum_usdt = 0
        title_len = len(export_title)
        for data in export_list:
            if title_len <= 3:
                break  # 如果导出excel的横向数据长度不到3个就跳出循环

            sum_usdt += float(data[3])
            export_data = [data[i] for i in title_len]
            xlswriter.writerow(export_data, sheet_name=sheet_name)
            logging.info(data)

        xlswriter.writerow([], sheet_name=sheet_name)  #写一空行，用于隔开总usdt
        xlswriter.writerow([u' 合计:', sum_usdt], sheet_name=sheet_name)
        xlswriter.save()

        return True


    def accounts_recursion(self, currency, to_balance):
        """账户递归"""
        time.sleep(3) # 休息3秒再递归
        self.bina_cancel_allorder(currency)
        balances_list = self.balances_list()
        for b in balances_list:
            asset    = b.get('asset')
            free     = float(b.get('free'))
            if asset != currency:
                continue

            diff_price = free - to_balance
            if diff_price > 0.1:
                symbol = get_symbol(asset, 'usdt', 'bina')
                self.symbol_order(symbol, diff_price)
                return self.accounts_recursion(currency, to_balance)
            return True
